package com.tbit.uqbike.webmanager.business.vehicle_operation_report.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tbit.uqbike.constant.enums.AccountDayStatEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.Account;
import com.tbit.uqbike.object.pojo.AccountDayStat;
import com.tbit.uqbike.object.pojo.vo.VehicleOperationReportVO;
import com.tbit.uqbike.service.business.impl.AdopterMsgServiceImpl;
import com.tbit.uqbike.webmanager.business.vehicle_operation_report.object.LowBatteryStat;
import com.tbit.uqbike.webmanager.business.vehicle_operation_report.service.VehicleOperationReportService;
import com.tbit.uqbike.webmanager.dao.core.AccountDao;
import com.tbit.uqbike.webmanager.dao.stat.AccountDayStatDao;
import com.tbit.uqbike.webmanager.business.vehicle_operation_report.dao.stat.LowBatteryHourDao;
import com.tbit.uqbike.webmanager.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author:BUGTian
 * @DATE: 2022/11/10
 */
@Slf4j
@Service
public class VehicleOperationReportServiceImpl implements VehicleOperationReportService {

    @Autowired
    private AccountDayStatDao accountDayStatDao;
    @Autowired
    private LowBatteryHourDao lowBatteryHourDao;
    @Autowired
    private AccountDao accountDao;

    @Override
    public List<VehicleOperationReportVO> queryByDay(List<Integer> adAccountIds, Date startTime, Date endTime, String timeA, String timeB) {
        // 区域信息
        Map<Integer, Account> accountMap = accountDao.getByAccountIds(adAccountIds).stream()
                .collect(Collectors.toMap(Account::getAccountId, Function.identity()));

        List<VehicleOperationReportVO> list = new ArrayList<>();
        List<String> betweenEveryDay = AdopterMsgServiceImpl.getBetweenEveryDay(startTime, endTime);
        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 使用 Lambda 表达式进行倒序排序
        Collections.sort(betweenEveryDay, (o1, o2) -> {
            LocalDate date1 = LocalDate.parse(o1, formatter);
            LocalDate date2 = LocalDate.parse(o2, formatter);
            return date2.compareTo(date1); // 倒序
        });
        List<AccountDayStat> accountDayStats = accountDayStatDao.selectList(new QueryWrapper<AccountDayStat>()
                .in("accountId", adAccountIds)
                .between("dataDate", parseTime(startTime), parseTime(endTime))
                .in("dataType", AccountDayStatEnum.getVehicleOperationType()));
        Map<Integer, Map<String, Long>> accountDayStatMap = new HashMap<>(); // map<区域id, map<时间, 统计值>>
        //预统计数据map
        accountDayStats.forEach(a -> {
            Map<String, Long> aMap = accountDayStatMap.computeIfAbsent(a.getAccountId(), k -> new HashMap<>());
            aMap.put(a.getDataDate() + "_" + a.getDataType(), a.getSumTotal());
            aMap.put(a.getDataDate() + "_" + a.getDataType() + "_" + "cnt", a.getCntTotal());
        });
        List<Date> lowBatteryHourTimeList = new ArrayList<>();
        try {
            for (String s : betweenEveryDay) {
                lowBatteryHourTimeList.add(DateUtil.parse(String.format("%s %s", s, timeA), "yyyy-MM-dd HH:mm"));
                lowBatteryHourTimeList.add(DateUtil.parse(String.format("%s %s", s, timeB), "yyyy-MM-dd HH:mm"));
            }
        } catch (Exception e) {
            log.error("[车辆运营报表] 时间格式有误", e);
            throw new BaseException("参数有误");
        }
        //车辆低电信息map
        Map<Integer, Map<String, LowBatteryStat>> lowBatteryHourMap = new HashMap<>();// map<区域id, map<时间, 车辆低电信息>>
        lowBatteryHourDao.selectByDataDate(adAccountIds, lowBatteryHourTimeList).forEach(stat -> {
            Map<String, LowBatteryStat> dateMap = lowBatteryHourMap.computeIfAbsent(stat.getAccountId(), k -> new HashMap<>());
            dateMap.put(stat.getDataDate(), stat);
        });
        Map<Integer, Map<String, LowBatteryStat>> lowBatteryDayAvgMap = new HashMap<>(); // map<区域id, map<时间, 车辆低电平均值>>
        lowBatteryHourDao.selectDayAvgByDate(adAccountIds, startTime, endTime).forEach(stat -> {
            Map<String, LowBatteryStat> dateMap = lowBatteryDayAvgMap.computeIfAbsent(stat.getAccountId(), k -> new HashMap<>());
            dateMap.put(stat.getDataDate(), stat);
        });
        for (String day : betweenEveryDay) {
            for (Account area : accountMap.values()) {
                list.add(new VehicleOperationReportVO()
                        .setAccountName(area.getName())
                        .setDay(day).setPutRate(getRate(AccountDayStatEnum.RATE_OF_VEHICLE_DELIVERY, accountDayStatMap.get(area.getAccountId()), day))
                        .setShelvesRate(getRate(AccountDayStatEnum.VEHICLE_LOADING_RATE, accountDayStatMap.get(area.getAccountId()), day))
                        .setRentRate(getRate(AccountDayStatEnum.VEHICLE_RENTAL_RATE, accountDayStatMap.get(area.getAccountId()), day))
                        .setProfitRate(getRate(AccountDayStatEnum.CYCLING_PROFIT_RATE, accountDayStatMap.get(area.getAccountId()), day))
                        .setIncomeAvgPerCar(getAvgMoney(day, area, accountDayStatMap))
                        .setOrderAvgPerCar(getData(day, area, accountDayStatMap, AccountDayStatEnum.NUMBER_OF_ORDERS_PER_VEHICLE))
                        .setRideMinuteAvgPerCar(getMinuteAvg(day, area, accountDayStatMap))
                        .setRideMeterAvgPerCar(getAvgMileage(day, area, accountDayStatMap))
                        .setMaintainRate(getRate(AccountDayStatEnum.REPAIR_COMPLETION_RATE, accountDayStatMap.get(area.getAccountId()), day))
                        .setDispatchRate(getRate(AccountDayStatEnum.EFFICIENCY_OF_DISPATCH, accountDayStatMap.get(area.getAccountId()), day))
                        .setMoveRate(getRate(AccountDayStatEnum.MOVING_COMPLETION_RATE, accountDayStatMap.get(area.getAccountId()), day))
                        .setLowRateA(getLowRate(lowBatteryHourMap.get(area.getAccountId()), day, timeA))
                        .setLowRateB(getLowRate(lowBatteryHourMap.get(area.getAccountId()), day, timeB))
                        .setLowBatteryAvg(getLowBatteryAvg(lowBatteryDayAvgMap.get(area.getAccountId()), day))
                );
            }
        }
        return list;
    }


    /**
     * 车均骑行里程 订单总里程/订单数
     */
    private String getAvgMileage(String day, Account area, Map<Integer, Map<String, Long>> accountDayStatMap){
        Map<String, Long> stringLongMap = accountDayStatMap.get(area.getAccountId());
        if (CollectionUtil.isEmpty(stringLongMap)){
            return "0";
        }
        Long orderCount = stringLongMap.get(day.replace("-", "") + "_" + AccountDayStatEnum.CYCLING_INCOME.getDataType() + "_cnt");
        Long mileage = stringLongMap.get(day.replace("-", "") + "_" + AccountDayStatEnum.ACCUMULATED_MILEAGE.getDataType());
        if (orderCount != null && mileage != null){
            return NumberUtil.div(mileage, orderCount, 2).toString();
        }
        return "0";
    }

    /**
     * 计算车均骑行时长 总骑行时长/订单数
     * @return string
     */
    private String getMinuteAvg(String day, Account area, Map<Integer, Map<String, Long>> accountDayStatMap){
        Map<String, Long> stringLongMap = accountDayStatMap.get(area.getAccountId());
        if (CollectionUtil.isEmpty(stringLongMap)){
            return "00:00:00";
        }
        //骑行订单数量
        Long rideCount = stringLongMap.get(day.replace("-", "") + "_" + AccountDayStatEnum.CYCLING_INCOME.getDataType() + "_cnt");
        //骑行时长 秒
        Long rideTime = stringLongMap.get(day.replace("-", "") + "_" + AccountDayStatEnum.MACHINE_RIDING_TIME.getDataType());
        if (rideTime != null && rideCount != null){
            BigDecimal div = NumberUtil.div(rideTime, rideCount, 0);
            int i = div.intValue();
            return String.format("%02d:%02d:%02d", i / 3600, i % 3600 / 60, i % 60);
        }
        return "00:00:00";
    }

    /**
     * 获取数据
     * @return String
     */
    private String getData(String day, Account area, Map<Integer, Map<String, Long>> accountDayStatMap, AccountDayStatEnum accountDayStatEnum){
        Map<String, Long> stringLongMap = accountDayStatMap.get(area.getAccountId());
        if (CollectionUtil.isEmpty(stringLongMap)){
            return "0";
        }
        Long count = stringLongMap.get(day.replace("-", "") + "_" + accountDayStatEnum.getDataType() + "_cnt");
        return count == null ? "0" : Double.toString(NumberUtil.div(count.intValue(), 100, 2));
    }

    /**
     * 获取车均收入
     * @return String
     */
    private String getAvgMoney(String day, Account area, Map<Integer, Map<String, Long>> accountDayStatMap) {
        Map<String, Long> stringLongMap = accountDayStatMap.get(area.getAccountId());
        if (CollectionUtil.isEmpty(stringLongMap)){
            return "0";
        }
        Long money = stringLongMap.get(day.replace("-", "") + "_" + AccountDayStatEnum.AVERAGE_VEHICLE_INCOME.getDataType());
        return money == null ? "0" : Double.toString(NumberUtil.div(money.intValue(), 100, 2));
    }

    private String getLowBatteryAvg(Map<String, LowBatteryStat> lowBatteryHourMap, String day) {
        if (lowBatteryHourMap == null) {
            return "0%";
        }
        LowBatteryStat stat = lowBatteryHourMap.get(day);
        return stat == null ? "0%" : stat.getCompleteEta() + "%";
    }

    private Integer parseTime(Date time) {
        return Integer.parseInt(DateUtil.format(time, "yyyyMMdd"));
    }

    /**
     * 获取比率
     *
     * @param accountDayStatEnum
     * @param accountDayStatMap
     * @param day
     * @return
     */
    private String getRate(AccountDayStatEnum accountDayStatEnum, Map<String, Long> accountDayStatMap, String day) {
        String rate = "0%";
        if (accountDayStatMap == null) {
            return rate;
        }
        Long count = accountDayStatMap.get(day.replace("-", "") + "_" + accountDayStatEnum.getDataType());
        if (count == null) {
            return rate;
        }
        return count.toString() + "%";
    }

    /**
     * 获取车辆低电占比比率
     *
     * @param lowBatteryHourMap
     * @param day
     * @param time
     * @return
     */
    private String getLowRate(Map<String, LowBatteryStat> lowBatteryHourMap, String day, String time) {
        String rate = "0%";
        String key = String.format("%s %s", day, time);
        if (lowBatteryHourMap == null) {
            return rate;
        }
        LowBatteryStat stat = lowBatteryHourMap.get(key);
        if (stat == null) {
            return rate;
        }
        String completeEta = stat.getCompleteEta();
        if (StringUtils.isNotEmpty(completeEta)) {
            if (completeEta.contains(".")) {
                completeEta = completeEta.substring(0, completeEta.lastIndexOf("."));
            }
        }
        return completeEta + "%";
    }


}
